/**@file

 @copyright
  INTEL CONFIDENTIAL
  Copyright 2012 - 2016 Intel Corporation.

  The source code contained or described herein and all documents related to the
  source code ("Material") are owned by Intel Corporation or its suppliers or
  licensors. Title to the Material remains with Intel Corporation or its suppliers
  and licensors. The Material may contain trade secrets and proprietary and
  confidential information of Intel Corporation and its suppliers and licensors,
  and is protected by worldwide copyright and trade secret laws and treaty
  provisions. No part of the Material may be used, copied, reproduced, modified,
  published, uploaded, posted, transmitted, distributed, or disclosed in any way
  without Intel's prior express written permission.

  No license under any patent, copyright, trade secret or other intellectual
  property right is granted to or conferred upon you by disclosure or delivery
  of the Materials, either expressly, by implication, inducement, estoppel or
  otherwise. Any license under such intellectual property rights must be
  express and approved by Intel in writing.

  Unless otherwise agreed by Intel in writing, you may not remove or alter
  this notice or any other notice embedded in Materials by Intel or
  Intel's suppliers or licensors in any way.

  This file contains 'Framework Code' and is licensed as such under the terms
  of your license agreement with Intel or your vendor. This file may not be 
  modified, except as allowed by additional terms of your license agreement.

@par Specification Reference:
**/
#include "VirtualKeyboard.h"
#include "VK_MAP.h"
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/VirtualKeyboardLayout.h>

#define ROW_KEYS_M               7
#define COLUMN_KEYS_M            3
#define LEFT_AND_RIGHT_SIDE_LINE 10
#define KEY_BOTTOM_WIDTH         5
#define FONT_BORDER              2

EFI_KEY_DESCRIPTOR MappingKey[] = {
    //
    // EFI_KEY_DESCRIPTOR (total number is USB_KEYBOARD_KEY_COUNT)
    //
    //
    // EFI_KEY_DESCRIPTOR (total number is USB_KEYBOARD_KEY_COUNT)
    //
    {EfiKeyC1,         'a',      'A',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB5,         'b',      'B',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB3,         'c',      'C',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC3,         'd',      'D',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD3,         'e',      'E',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC4,         'f',      'F',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC5,         'g',      'G',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC6,         'h',      'H',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD8,         'i',      'I',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC7,         'j',      'J',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC8,         'k',      'K',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC9,         'l',      'L',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB7,         'm',      'M',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB6,         'n',      'N',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD9,         'o',      'O',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD10,        'p',      'P',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD1,         'q',      'Q',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD4,         'r',      'R',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyC2,         's',      'S',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD5,         't',      'T',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD7,         'u',      'U',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB4,         'v',      'V',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD2,         'w',      'W',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB2,         'x',      'X',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyD6,         'y',      'Y',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyB1,         'z',      'Z',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
    {EfiKeyE1,         '1',      '!',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE2,         '2',      '@',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE3,         '3',      '#',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE4,         '4',      '$',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE5,         '5',      '%',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE6,         '6',      '^',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE7,         '7',      '&',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE8,         '8',      '*',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE9,         '9',      '(',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE10,        '0',      ')',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyEnter,      0x0d,     0x0d, 0, 0,  EFI_NULL_MODIFIER,   0},
    {EfiKeyEsc,        INT_KEY_ESC,INT_KEY_ESC,0,0,EFI_NULL_MODIFIER,   0},
    {EfiKeyBackSpace,  0x08,     0x08, 0, 0,  EFI_NULL_MODIFIER,   0},
    {EfiKeyTab,        0x09,     0x09, 0, 0,  EFI_NULL_MODIFIER,   0},
    {EfiKeySpaceBar,   ' ',      ' ',  0, 0,  EFI_NULL_MODIFIER,   0},
    {EfiKeyE11,        '-',      '_',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE12,        '=',      '+',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyD11,        '[',      '{',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyD12,        ']',      '}',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyD13,        '\\',     '|',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyC10,        ';',      ':',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyC11,        '\'',     '"',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyE0,         '`',      '~',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyB8,         ',',      '<',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyB9,         '.',      '>',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyB10,        '/',      '?',  0, 0,  EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},
    {EfiKeyCapsLock,   0x00,     0x00, 0, 0,  EFI_CAPS_LOCK_MODIFIER,            0},
    {EfiKeyF1,         INT_KEY_F1,0x00,0, 0,  EFI_FUNCTION_KEY_ONE_MODIFIER,     0},
    {EfiKeyF2,         INT_KEY_F2,0x00,0, 0,  EFI_FUNCTION_KEY_TWO_MODIFIER,     0},
    {EfiKeyF3,         INT_KEY_F3,0x00,0, 0,  EFI_FUNCTION_KEY_THREE_MODIFIER,   0},
    {EfiKeyF4,         INT_KEY_F4,0x00,0, 0,  EFI_FUNCTION_KEY_FOUR_MODIFIER,    0},
    {EfiKeyF5,         INT_KEY_F5,0x00,0, 0,  EFI_FUNCTION_KEY_FIVE_MODIFIER,    0},
    {EfiKeyF6,         INT_KEY_F6,0x00,0, 0,  EFI_FUNCTION_KEY_SIX_MODIFIER,     0},
    {EfiKeyF7,         INT_KEY_F7,0x00,0, 0,  EFI_FUNCTION_KEY_SEVEN_MODIFIER,   0},
    {EfiKeyF8,         INT_KEY_F8,0x00,0, 0,  EFI_FUNCTION_KEY_EIGHT_MODIFIER,   0},
    {EfiKeyF9,         INT_KEY_F9,0x00,0, 0,  EFI_FUNCTION_KEY_NINE_MODIFIER,    0},
    {EfiKeyF10,        INT_KEY_F10,0x00,0,0,  EFI_FUNCTION_KEY_TEN_MODIFIER,     0},
    {EfiKeyF11,        INT_KEY_F11,0x00,0,0,  EFI_FUNCTION_KEY_ELEVEN_MODIFIER,  0},
    {EfiKeyF12,        INT_KEY_F12,0x00,0,0,  EFI_FUNCTION_KEY_TWELVE_MODIFIER,  0},
    {EfiKeyPrint,      0x00,     0x00, 0, 0,  EFI_PRINT_MODIFIER,                0},
    {EfiKeySLck,       0x00,     0x00, 0, 0,  EFI_SCROLL_LOCK_MODIFIER,          0},
    {EfiKeyPause,      0x00,     0x00, 0, 0,  EFI_PAUSE_MODIFIER,                0},
    {EfiKeyIns,        0x00,     0x00, 0, 0,  EFI_INSERT_MODIFIER,               0},
    {EfiKeyHome,       0x00,     0x00, 0, 0,  EFI_HOME_MODIFIER,                 0},
    {EfiKeyPgUp,       0x00,     0x00, 0, 0,  EFI_PAGE_UP_MODIFIER,              0},
    {EfiKeyDel,        0x00,     0x00, 0, 0,  EFI_DELETE_MODIFIER,               0},
    {EfiKeyEnd,        0x00,     0x00, 0, 0,  EFI_END_MODIFIER,                  0},
    {EfiKeyPgDn,       0x00,     0x00, 0, 0,  EFI_PAGE_DOWN_MODIFIER,            0},
    {EfiKeyRightArrow, INT_KEY_RIGHT,0x00,0,0,EFI_RIGHT_ARROW_MODIFIER,          0},
    {EfiKeyLeftArrow,  INT_KEY_LEFT,0x00,0,0, EFI_LEFT_ARROW_MODIFIER,           0},
    {EfiKeyDownArrow,  INT_KEY_DOWN,0x00,0,0, EFI_DOWN_ARROW_MODIFIER,           0},
    {EfiKeyUpArrow,    INT_KEY_UP,0x00,0, 0,  EFI_UP_ARROW_MODIFIER,             0},
    {EfiKeyNLck,       0x00,     0x00, 0, 0,  EFI_NUM_LOCK_MODIFIER,             0},
    {EfiKeyAsterisk,   '*',      '*',  0, 0,  EFI_NULL_MODIFIER,                 0},
    {EfiKeyMinus,      '-',      '-',  0, 0,  EFI_NULL_MODIFIER,                 0},
    {EfiKeyPlus,       '+',      '+',  0, 0,  EFI_NULL_MODIFIER,                 0},
    {EfiKeyEnter,      0x0d,     0x0d, 0, 0,  EFI_NULL_MODIFIER,                 0},
    {EfiKeyOne,        '1',      '1',  0, 0,  EFI_END_MODIFIER,         EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyTwo,        '2',      '2',  0, 0,  EFI_DOWN_ARROW_MODIFIER,  EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyThree,      '3',      '3',  0, 0,  EFI_PAGE_DOWN_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyFour,       '4',      '4',  0, 0,  EFI_LEFT_ARROW_MODIFIER,  EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyFive,       '5',      '5',  0, 0,  EFI_NULL_MODIFIER,        EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeySix,        '6',      '6',  0, 0,  EFI_RIGHT_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeySeven,      '7',      '7',  0, 0,  EFI_HOME_MODIFIER,        EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyEight,      '8',      '8',  0, 0,  EFI_UP_ARROW_MODIFIER,    EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyNine,       '9',      '9',  0, 0,  EFI_PAGE_UP_MODIFIER,     EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyZero,       '0',      '0',  0, 0,  EFI_INSERT_MODIFIER,      EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyPeriod,     '.',      '.',  0, 0,  EFI_DELETE_MODIFIER,      EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
    {EfiKeyA4,         0x00,     0x00, 0, 0,  EFI_MENU_MODIFIER,            0},
    {EfiKeyLCtrl,      0,        0,    0, 0,  EFI_LEFT_CONTROL_MODIFIER,    0},
    {EfiKeyLShift,     0,        0,    0, 0,  EFI_LEFT_SHIFT_MODIFIER,      0},
    {EfiKeyLAlt,       0,        0,    0, 0,  EFI_LEFT_ALT_MODIFIER,        0},
    {EfiKeyA0,         0,        0,    0, 0,  EFI_LEFT_LOGO_MODIFIER,       0},
    {EfiKeyRCtrl,      0,        0,    0, 0,  EFI_RIGHT_CONTROL_MODIFIER,   0},
    {EfiKeyRShift,     0,        0,    0, 0,  EFI_RIGHT_SHIFT_MODIFIER,     0},
    {EfiKeyA2,         0,        0,    0, 0,  EFI_RIGHT_ALT_MODIFIER,       0},
    {EfiKeyA3,         0,        0,    0, 0,  EFI_RIGHT_LOGO_MODIFIER,      0},
    }; // EFI_KEY_DESCRIPTOR MappingKey[] = {  End of structure


/**
  Reset the input device and optionally run diagnostics

  @param  This                 Protocol instance pointer.
  @param  ExtendedVerification Driver may perform diagnostics on reset.

  @retval EFI_SUCCESS          The device was reset.
  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.

**/
EFI_STATUS
EFIAPI
VkReset (
  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
  IN BOOLEAN                        ExtendedVerification
  )
{
  EFI_STATUS Status;

  //
  //  Display entry
  //
  DEBUG (( DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkReset entered\n" ));

  //
  //  Assume success
  //
  Status = EFI_SUCCESS;

  //
  //  Display exit
  //
  DEBUG (( DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkReset exiting, Status: %r\n", Status ));

  //
  //  Return the startup status
  //
  return Status;
}


/**
  Push the event mapping key index to the input key buffer.

  @param  KeyBuffer            Key buffer point
  @param  AltKeyBuf            Alt key buffer point.
  @param  VkStratIndex         The start index of valid key buffer.
  @param  VkEndIndex           The end insex of valid key buffer.
  @param  ShiftKeyFlag         The flag for shift event.
  @param  Unicode              The font's unicode number.

  @retval EFI_SUCCESS          The maping key index did put the key buffer.
  @retval EFI_VOLUME_FULL      The key buffer is full.

**/
EFI_STATUS
VkPushtheKey(
  IN   UINT16 *KeyBuffer,
  IN   UINT8  *AltKeyBuf,
  OUT  UINT8  *VkStratIndex,
  OUT  UINT8  *VkEndIndex,
  OUT  UINT8  *ShiftKeyFlag,
  OUT  UINT8  *PageNumber,
  IN   UINT16 Unicode
  )
{
  UINT8  IndexSt;
  UINT8  IndexEd;
  UINT8  NextIndexEd;
  UINT16 SrKeyMapCount;

  IndexSt = *VkStratIndex;
  IndexEd = *VkEndIndex;
  NextIndexEd = *VkEndIndex + 1;

  //
  //      Start Ptr
  //      |
  //  [0][1][2][3][4][5][6]......[MAX_KEY_BUF_SIZE - 1] <-- J=KeyBuffer
  //      |
  //      |
  //      End Ptr

  if (NextIndexEd == MAX_KEY_BUF_SIZE) {
    NextIndexEd = 0;
  }

  if (NextIndexEd == IndexSt) {
    return EFI_VOLUME_FULL;
  }

  if (Unicode == INT_KEY_SHIFT) {
    *ShiftKeyFlag ^= 1;
    DEBUG (( DEBUG_VK_POINTS,
           "\n VkPushtheKey [Unicode:0x%04x], Change Shift Key\n",
           Unicode));
    return EFI_SUCCESS;
  }

  if (Unicode == INT_KEY_TWO_PAGES) {
    *PageNumber += 1;
    if ((*PageNumber) >= MAX_VKBD_PAGE_NUM) {
      (*PageNumber) = 0;
    }

    return EFI_SUCCESS;
  }

  DEBUG (( DEBUG_VK_POINTS,
           "\n VkPushtheKey [ShiftKeyFlag:0x%04x]\n",
           *ShiftKeyFlag));
  if ((Unicode > 0x40) && (Unicode < 0x5b)) {
    if ((*ShiftKeyFlag & 0x01) == 0) {
      Unicode |= 0x60;
    }
  }

  for (SrKeyMapCount = 0; SrKeyMapCount < DIM(MappingKey); SrKeyMapCount++) {
    if (MappingKey[SrKeyMapCount].Unicode == Unicode) {
      break;
    }
  }

  //
  // default is 0
  //
  AltKeyBuf[IndexEd] = 0;

  // The Key process stuff
  // Like [CAPS], ALT or Ctrl on

  if (SrKeyMapCount == DIM(MappingKey)) {
    for (SrKeyMapCount = 0; SrKeyMapCount < DIM(MappingKey); SrKeyMapCount++) {
      if (MappingKey[SrKeyMapCount].ShiftedUnicode == Unicode) {
        break;
      }
    }

    if (SrKeyMapCount != DIM(MappingKey)) {
      AltKeyBuf[IndexEd] |= 4;
    }
  }

  //
  // set BIT 0 is [CAP]   ON
  //     BIT 1 is [ALT]   ON
  //     BIT 2 is [Shift] ON
  DEBUG (( DEBUG_VK_POINTS,
           "\n VkPushtheKey [Unicode:0x%04x], %c\n",
           Unicode,Unicode));

  DEBUG (( DEBUG_VK_POINTS,
           "\n VkPushtheKey [IndexSt:0x%02x], [IndexEd:0x%02x]\n",
           IndexSt,IndexEd));

  DEBUG (( DEBUG_VK_POINTS,
           "\n VkPushtheKey [IndexEd:0x%02x], [MapCount:0x%02x], %c,  AltKeyBuf[IndexEd]=0x%02x\n",
           IndexEd,SrKeyMapCount,MappingKey[SrKeyMapCount].Unicode, AltKeyBuf[IndexEd] ));
  // Push Mapping ScanCode
  KeyBuffer[IndexEd] = SrKeyMapCount;
  *VkEndIndex = NextIndexEd;

  return EFI_SUCCESS;
}


/**
  Reads the key from the keybuffer.

  @param  KeyBuffer        Keys buffer array
  @param  AltKeyBuf        this array put some special key flag mapping to the key buffer
  @param  VkStratIndex     Key buffer Index for the first read the key
  @param  VkEndIndex       Key buffer Index for determine the key buffer is empty
  @param  KeyData          The EFI stand key infomation when code get the key will put
                           correct mapping key.

  @retval EFI_SUCCESS      The keystroke information was returned.
  @retval EFI_NOT_READY    There was no keystroke data available.

**/
EFI_STATUS
VkReadKeyBuf(
  IN   UINT16        *KeyBuffer,
  IN   UINT8         *AltKeyBuf,
  OUT  UINT8         *VkStratIndex,
  OUT  UINT8         *VkEndIndex,
  OUT  EFI_KEY_DATA  *KeyData
  )
{
  UINT8  IndexSt;
  UINT8  IndexEd;
  UINT8  AltKey;
  UINT16 KeyMappingIndex;

  IndexSt = *VkStratIndex;
  IndexEd = *VkEndIndex;

  //
  //      Start Ptr (IndexSt)
  //      |
  //  [0][1][2][3][4][5][6]......[MAX_KEY_BUF_SIZE - 1] <-- J=KeyBuffer
  //      |
  //      |
  //      End Ptr (IndexEd)

  if (IndexEd == IndexSt) {
    return EFI_NOT_READY;
  }


  //
  // Check the Alt key buffer did have any flag.
  //
  AltKey = AltKeyBuf[IndexSt];
  KeyMappingIndex = KeyBuffer[IndexSt];

  KeyData->Key.UnicodeChar = MappingKey[KeyMappingIndex].Unicode;

  KeyData->KeyState.KeyShiftState=EFI_SHIFT_STATE_VALID;
  KeyData->KeyState.KeyToggleState=EFI_TOGGLE_STATE_VALID;


  DEBUG (( DEBUG_VK_POINTS,
           "\n VK_KEY [Unicode:%0d]\n",
           KeyMappingIndex));

  DEBUG (( DEBUG_VK_POINTS,
           "\n VK_KEY [0x%04x] \n",
           MappingKey[KeyMappingIndex].Unicode));
  if (AltKey != 0) {
       KeyData->Key.UnicodeChar = MappingKey[KeyMappingIndex].ShiftedUnicode;
       KeyData->Key.ScanCode = SCAN_NULL;
  } else {
   //
   // Some special keys need to transfer to scan code.
   //
   switch (KeyData->Key.UnicodeChar) {
     case INT_KEY_UP:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_UP;
          break;
     case INT_KEY_DOWN:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_DOWN;
          break;
     case INT_KEY_LEFT:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_RIGHT;
          break;
     case INT_KEY_RIGHT:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_LEFT;
          break;
     case INT_KEY_ESC:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_ESC;
          break;
     case INT_KEY_F1:
          KeyData->Key.UnicodeChar = 0x00;
          KeyData->Key.ScanCode = SCAN_F1;
          break;
     case INT_KEY_F2:
          KeyData->Key.UnicodeChar = 0x00;
          KeyData->Key.ScanCode = SCAN_F2;
          break;
     case INT_KEY_F3:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F3;
          break;
     case INT_KEY_F4:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F4;
          break;
     case INT_KEY_F5:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F5;
          break;
     case INT_KEY_F6:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F6;
          break;
     case INT_KEY_F7:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F7;
          break;
     case INT_KEY_F8:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F8;
          break;
     case INT_KEY_F9:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F9;
          break;
     case INT_KEY_F10:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F10;
          break;
     case INT_KEY_F11:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F11;
          break;
     case INT_KEY_F12:
          KeyData->Key.UnicodeChar = 0;
          KeyData->Key.ScanCode = SCAN_F12;
          break;
     default:
       KeyData->Key.UnicodeChar = MappingKey[KeyMappingIndex].Unicode;
       KeyData->Key.ScanCode = SCAN_NULL;
     break;
   }

   DEBUG (( DEBUG_VK_POINTS,
           "\n VK_KEY [IndexSt:0x%02x], [IndexEd:0x%02x]\n",
           IndexSt,IndexEd));

   DEBUG (( DEBUG_VK_POINTS,
           "Read VK_KEY  [UnicodeChar:0x%04x],[scancode:0x%04x]\n",KeyData->Key.UnicodeChar,KeyData->Key.ScanCode));

  }


  IndexSt++;

  if (IndexSt == MAX_KEY_BUF_SIZE) {
    IndexSt = 0;
  }

  *VkStratIndex = IndexSt;
  return EFI_SUCCESS;
}

/**
  Reads the next keystroke from the input device. The WaitForKey Event can
  be used to test for existence of a keystroke via WaitForEvent () call.

  @param  This Protocol instance pointer.
  @param  Key  Driver may perform diagnostics on reset.

  @retval EFI_SUCCESS      The keystroke information was returned.
  @retval EFI_NOT_READY    There was no keystroke data available.
  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
                           hardware errors.

**/
EFI_STATUS
EFIAPI
VkReadKeyStroke (
  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
  OUT EFI_INPUT_KEY *Key
  )
{
  EFI_STATUS Status;
  VK_CONTEXT *VkContext;
  EFI_KEY_DATA  KeyData;


  VkContext = VK_CONTEXT_FROM_PROTOCOL (This);
  DEBUG (( DEBUG_VK_POINTS, "VkReadKeyStroke entered\n" ));

  //
  //  Assume no data available
  //
  Status = VkReadKeyBuf(VkContext->Keybuffer,
                        VkContext->AltKeyBuf,
                        &VkContext->KeyStartIndex,
                        &VkContext->KeyEndIndex,
                        &KeyData
                       );

  if (EFI_ERROR(Status)) {
    Status = EFI_NOT_READY;
  }

  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));

  DEBUG (( DEBUG_VK_POINTS, "VkReadKeyStroke exiting, Status: %r, ScanCode=%x\n", Status, Key->ScanCode ));

  //
  //  Return the startup status
  //
  return Status;
}

EFI_STATUS
GetMappingFont(
  IN  VK_CONTEXT   *VkContext,
  IN  VKSTRU       *KeyInfoptr,
  OUT UINT32       **FontPtr
  )
{
  switch (VkContext->PageNumber) {
    case 1:
     *FontPtr = KeyInfoptr->Page1Font;
    break;
    case 2:
     *FontPtr = KeyInfoptr->Page2Font;
    break;
    case 3:
     *FontPtr = KeyInfoptr->Page3Font;
    break;
    default:
     *FontPtr = KeyInfoptr->Page0Font;
    break;
  }

  return EFI_SUCCESS;
}

/**
  TouchVkWaitForKey - SignalEvent when the keybuffer has keys.

  @param[in] Event    Event whose notification function is being invoked.
  @param[in] Context  Pointer to the notification function's context,
                      which is implementation-dependent.  Context corresponds
                      to NotifyContext in CreateEventEx().
**/
VOID
EFIAPI
TouchVkWaitForKey (
  IN  EFI_EVENT               Event,
  IN  VOID                    *Context
  )
{
  VK_CONTEXT *VkContext;

  VkContext = (VK_CONTEXT*) Context;

  if (VkContext->KeyStartIndex == VkContext->KeyEndIndex) {
    return;
  }

  DEBUG ((DEBUG_VK_POINTS, "Signal TouchVkWaitForKey\n"));

  //
  // If there is pending key, signal the event.
  //
  gBS->SignalEvent (Event);
}

/**
  Timer event

  This routine is called at TPL_VK_SYNC.

  This routine polls for touch panel input.

  @param[in] Event    Event whose notification function is being invoked.
  @param[in] Context  Pointer to the notification function's context,
                      which is implementation-dependent.  Context corresponds
                      to NotifyContext in CreateEventEx().
**/
VOID
EFIAPI
VkTimer (
  IN EFI_EVENT      Event,
  IN VOID           *Context
  )
{
  EFI_ABSOLUTE_POINTER_PROTOCOL         *AbsolutePointer;
  EFI_ABSOLUTE_POINTER_STATE            Point;
  EFI_STATUS                            Status;
  UINT64                                RescaledTouchX;
  UINT64                                RescaledTouchY;
  VK_CONTEXT                            *VkContext;
  UINT32                                Index;
  VKSTRU                                *KeyInfoptr;
  UINT32                                *FontPtr;
  UINT32                                Color;
  UINT8                                 TmpShiftFlag;
  UINT8                                 TmpPageNum;
  UINT32                                HorizontalResolution;
  UINT32                                VerticalResolution;
  UINTN                                 Size;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *Blt;
  static UINT16                          ReDrawCheck = 0;

  TmpShiftFlag = 0;
  Color = 0;

  //
  // Display the keyboard
  //
  VkContext = (VK_CONTEXT *)Context;
  KeyInfoptr = VkContext->XmanPtr;

  //
  // Check if right-bottomed region is black, if yes, clean screen happened, need to re-draw keyboard.
  // Check it every 10 * 100ms.
  //
  ReDrawCheck++;
  if (ReDrawCheck == 10) {
    HorizontalResolution  = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
    VerticalResolution    = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
    Size                  = 10 * 10 * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
    BltBuffer             = NULL;

    BltBuffer = AllocateZeroPool (Size);
    ASSERT (BltBuffer != NULL);
    if (BltBuffer == NULL) {
      return;
    }
    Status = VkContext->GraphicsOutput->Blt (
                                          VkContext->GraphicsOutput,
                                          BltBuffer,
                                          EfiBltVideoToBltBuffer,
                                          (HorizontalResolution - 10),
                                          (VerticalResolution - 10),
                                          0,
                                          0,
                                          10,
                                          10,
                                          10 * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
                                          );

    for (Index = 0; Index < 10 * 10; Index++) {
      Blt = BltBuffer + Index;
      if ((Blt->Blue != 0x00) || (Blt->Green != 0x00) || (Blt->Red != 0x00)) {
        break;
      } else {
        VkContext->DisplayKeyboard = FALSE;
      }
    }

    if (BltBuffer != NULL) {
      FreePool (BltBuffer);
    }
    ReDrawCheck = 0;
  }

  if ((VkContext->DisplayKeyboard == FALSE) && (ReDrawCheck == 5)) {
    //
    // Draw the keyboard.
    // Delay 5 * 100 ms to skip GOP change mode.
    //
    Status = DrawKeyboardLayout (VkContext);
    if (!EFI_ERROR (Status)) {
      VkContext->DisplayKeyboard = TRUE;
    }
  }

  AbsolutePointer = VkContext->AbsolutePointer;

  //
  // CheckEvent() should not be used. Instead use WaitForEvent()
  //
  Status = gBS->CheckEvent (AbsolutePointer->WaitForInput);
  if (EFI_ERROR(Status)) {
    return;
  }

  Status = AbsolutePointer->GetState (AbsolutePointer, &Point);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, " &%r:", Status));
    return;
  }

  DEBUG ((DEBUG_ERROR,
          "0x%08Lx: X 0x%08Lx: Y 0x%08Lx: Z 0x%02x: Buttons\n",
          Point.CurrentX,
          Point.CurrentY,
          Point.CurrentZ,
          Point.ActiveButtons));

  if (VkContext->TouchActive != 0 && ((Point.ActiveButtons & EFI_ABSP_TouchActive) != 0)) {
    //
    // Panel is still being touched - don't do anything
    //  TODO: add code to check for repeat delay / repeat rate,
    //  but only after I2C speed problem is solved
    //
    return;
  }

  if ((Point.ActiveButtons & EFI_ABSP_TouchActive) == 0) {
    //
    // Panel not touched or no longer touched.
    //
    VkContext->TouchActive = 0;
    VkContext->KeyPressed = FALSE;
    return;
  }

  //
  // if code goes here, it means there's a new touch event
  //

  VkContext->TouchActive = TRUE;

  //
  // Validate the point
  //
  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxX <= Point.CurrentX) {
    DEBUG ((DEBUG_VK_POINTS,
            "ERROR - X value exceeds maximum: X: 0x%016Lx, MaxX: 0x%016Lx\n",
            Point.CurrentX,
            VkContext->AbsolutePointer->Mode->AbsoluteMaxX));
    return;
  }
  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxY <= Point.CurrentY) {
    DEBUG ((DEBUG_VK_POINTS,
            "ERROR - Y value exceeds maximum: Y: 0x%016Lx, MaxY: 0x%016Lx\n",
            Point.CurrentY,
            VkContext->AbsolutePointer->Mode->AbsoluteMaxY));
    return;
  }

  RescaledTouchX = Point.CurrentX;
  RescaledTouchY = Point.CurrentY;
  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxX != 0 && VkContext->AbsolutePointer->Mode->AbsoluteMaxY!=0) {
    RescaledTouchX = (UINT16)(((UINT64)(Point.CurrentX * 0xFFF)) / VkContext->AbsolutePointer->Mode->AbsoluteMaxX);
    RescaledTouchY = (UINT16)(((UINT64)(Point.CurrentY * 0xFFF)) / VkContext->AbsolutePointer->Mode->AbsoluteMaxY);
    DEBUG ((DEBUG_ERROR, "touch event rescaled, XYB %04x:%04x:%x\n", RescaledTouchX, RescaledTouchY, Point.ActiveButtons ));
  }
  //
  //  Determine if this point is in a key row
  //
  DEBUG (( DEBUG_VK_POINTS,"VK_TEST::Determine if this point is in a key row\n"));
  for (Index = 0; Index <  VkContext->NumOfKeysInfo; Index++) {

    if (((KeyInfoptr[Index].Toh_StartX < RescaledTouchX) && (RescaledTouchX <KeyInfoptr[Index].Toh_EndX)) && \
        ((KeyInfoptr[Index].Toh_StartY < RescaledTouchY) && (RescaledTouchY <KeyInfoptr[Index].Toh_EndY))) {
      //
      // Check the Page number, default is 0
      //
      GetMappingFont (VkContext, &KeyInfoptr[Index], &FontPtr);

      //
      // Flag the key as pressed
      //
      VkContext->KeyPressed = TRUE;
      if (Index == (VkContext->NumOfKeysInfo - 1)) {
        if (VkContext->ShowTheKeyboard == FALSE) {
          VkContext->ShowTheKeyboard = TRUE;
          Status = DrawKeyboardLayout(VkContext);
          DEBUG (( DEBUG_VK_POINTS,"VkTimer DrawKeyboardLayout::%r\n",Status));
        } else {
          HiddenRectangle(VkContext);
          VkContext->ShowTheKeyboard = FALSE;
          VkContext->KeyTouchedTimeOut = VK_REPET_TIMEOUT;
        }
      } else if ((FontPtr != NULL) && (VkContext->ShowTheKeyboard == TRUE) ) {
        TmpShiftFlag = VkContext->ShiftKeyFlag;
        TmpPageNum = VkContext->PageNumber;

        VkPushtheKey (
          VkContext->Keybuffer,
          VkContext->AltKeyBuf,
          &VkContext->KeyStartIndex,
          &VkContext->KeyEndIndex,
          &VkContext->ShiftKeyFlag,
          &VkContext->PageNumber,
          (UINT16)FontPtr[0]
          );
        if (TmpShiftFlag != VkContext->ShiftKeyFlag) {
          VkContext->GraphicsOutput->Blt (
                                       VkContext->GraphicsOutput,
                                       (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&Color,
                                       EfiBltVideoFill,
                                       0,//StartX,
                                       0,//StartY,
                                       KeyInfoptr[Index].Dis_StartX + KEY_BOTTOM_WIDTH,//EndX,
                                       KeyInfoptr[Index].Dis_StartY + KEY_BOTTOM_WIDTH,
                                       (KeyInfoptr[Index].Dis_EndX - KeyInfoptr[Index].Dis_StartX - KEY_BOTTOM_WIDTH), //EndX - 10,
                                       (KeyInfoptr[Index].Dis_EndY - KeyInfoptr[Index].Dis_StartY - KEY_BOTTOM_WIDTH),//LineWidth,
                                       0
                                       );

          DrawRectangle (
            VkContext->GraphicsOutput,
            KeyInfoptr[Index].Dis_StartX + KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_StartY + KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_EndX - KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_EndY - KEY_BOTTOM_WIDTH,
            1
            );
          //
          // Shift flag change
          //
          DrawCharacter (
            VkContext->GraphicsOutput,
            KeyInfoptr[Index].Dis_StartX + KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_StartY + KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_EndX - KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Dis_EndY - KEY_BOTTOM_WIDTH,
            KeyInfoptr[Index].Page0Font,
            (VkContext->ShiftKeyFlag & 0x01) ? COLOR_WHITE : 0,
            1
            );
        } else if (TmpPageNum != VkContext->PageNumber) {
          DrawKeyboardLayout(VkContext);
        }
        DEBUG ((DEBUG_VK_POINTS, "Key: %d\n", Index));
      }

    }
  }

}

/**
  Draw word in the Key button

  @param  GraphicsOutput        Graphic Protocol for draw the alphabet.
  @param  StartX                The button upper-left X location.
  @param  StartY                The button upper-left Y location.
  @param  EndX                  The button lower-right X location.
  @param  EndY                  The button lower-right Y location.
  @param  *FontPtr              It is bit map structure for the alphabet drawing display.
  @param  Color                 Set the alphabet color.
  @param  Flag                  Flag set to 1, draw the color to the alphabet.
                                Flag set to 0, reverse the Flag set to 0

  @retval EFI_SUCCESS           Draw the alphabet is done.
  @retval EFI_INVALID_PARAMETER The FontPtr is NULL.

**/
EFI_STATUS
DrawCharacter (
  IN   EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
  IN   UINT32                       StartX,
  IN   UINT32                       StartY,
  IN   UINT32                       EndX,
  IN   UINT32                       EndY,
  IN   UINT32                       *FontPtr,
  IN   UINT32                       Color,
  IN   UINT8                        Flag
  )

{
  UINT32            KeyStartX;
  UINT32            KeyStartY;
  UINT32            CountRow;
  UINT32            CountColumn;
  UINT32            PixelHigh;
  UINT32            PixelWidth;
  UINT32            Width;
  UINT32            High;
  UINT32            SetColor;
  EFI_STATUS        Status;
  UINT32            *FontDescPtr;

  SetColor = Color;

  if (FontPtr == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  //
  //    ______________
  //    |              }-------------------->
  //    |   .<---------KeyStartX, KeyStartY
  //    |
  //    |
  //    |
  //    |
  //    |
  //    |
  //    |_____________
  //
  //
  //
  Width = FontPtr[2];
  High = FontPtr[1];

  if ((Width == 0) || (High == 0)) {
    return EFI_SUCCESS;
  }
  FontDescPtr = &FontPtr[3];

  KeyStartX = StartX + FONT_BORDER;
  KeyStartY = StartY + FONT_BORDER;
  PixelWidth = ((EndX - FONT_BORDER) - KeyStartX) / Width;
  PixelHigh = ((EndY - FONT_BORDER) - KeyStartY) / High;

  DEBUG (( DEBUG_VK_TIMER_ENTRY_EXIT,"[PixelWidth : 0x%08x ][ PixelHigh : 0x%08x]\n",PixelWidth, PixelHigh));
  DEBUG (( DEBUG_VK_TIMER_ENTRY_EXIT,"[KeyStartX : 0x%08x ][ KeyStartY : 0x%08x]\n",KeyStartX,KeyStartY));

  for (CountRow = 0; CountRow < High; CountRow ++, KeyStartY += PixelHigh) {

    KeyStartX = StartX + FONT_BORDER;
    for (CountColumn = 0; CountColumn <  Width; CountColumn++, KeyStartX += PixelWidth) {
      if (((FontDescPtr[CountRow] >> (Width - CountColumn))& 0x01) == Flag) {

        Status = GraphicsOutput->Blt ( GraphicsOutput,
                                       (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&SetColor,
                                       EfiBltVideoFill,
                                       0,
                                       0,
                                       KeyStartX,
                                       KeyStartY,
                                       PixelWidth,
                                       PixelHigh,
                                       0 );


      }


    }
  }

  return EFI_SUCCESS;
}

/**
  Clear the key button

  @param  VkContext             Code context.

  @retval EFI_SUCCESS           Clear rectangle is done.

**/
EFI_STATUS
HiddenRectangle (
  IN VK_CONTEXT *VkContext
  )
{
  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
  VKSTRU                       *Xmanptr;
  EFI_STATUS                   Status;
  UINTN                        Index;
  UINT32                       Color;

  Color = 0;
  GraphicsOutput = VkContext->GraphicsOutput;
  Xmanptr = VkContext->XmanPtr;

  for (Index = 0; Index < (VkContext->NumOfKeysInfo - 1); Index++ ) {
    Status = GraphicsOutput->Blt (
                               GraphicsOutput,
                               (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&Color,
                               EfiBltVideoFill,
                               0,//StartX,
                               0,//StartY,
                               Xmanptr[Index].Dis_StartX,//EndX,
                               Xmanptr[Index].Dis_StartY,
                               (Xmanptr[Index].Dis_EndX - Xmanptr[Index].Dis_StartX), //EndX - 10,
                               (Xmanptr[Index].Dis_EndY - Xmanptr[Index].Dis_StartY),//LineWidth,
                               0
                               );
  }
  return EFI_SUCCESS;
}

/**
  Draw the key button

  @param  GraphicsOutput        Graphic Protocol for draw the alphabet.
  @param  StartX                The button upper-left X location.
  @param  StartY                The button upper-left Y location.
  @param  EndX                  The button lower-right X location.
  @param  EndY                  The button lower-right Y location.
  @param  SetColor              Set key button color.

  @retval EFI_SUCCESS           Draw the alphabet is done.

**/
EFI_STATUS
DrawRectangle (
  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
  IN  UINTN  StartX,
  IN  UINTN  StartY,
  IN  UINTN  EndX,
  IN  UINTN  EndY,
  IN  UINTN  SetColor
  )
{
  EFI_STATUS Status;
  UINT32     Color;


  Color = COLOR_LIGHT_GRAY;
  // (StartX, StartY, EndX, StartY)
  // Draw the top line
  Status = GraphicsOutput->Blt (
                             GraphicsOutput,
                             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&Color,
                             EfiBltVideoFill,
                             0,//StartX,
                             0,//StartY,
                             StartX,//EndX,
                             StartY,
                             (EndX - StartX), //EndX - 10,
                             (EndY - StartY),//LineWidth,
                             0
                             );

  return EFI_SUCCESS;
}

/**
  Draw key board on the display

  @param  VkContext             Graphic Protocol for draw the alphabet.
  @param  StartX                The button upper-left X location.
  @param  StartY                The button upper-left Y location.
  @param  EndX                  The button lower-right X location.
  @param  EndY                  The button lower-right Y location.
  @param  SetColor              Set key button color.

  @retval EFI_SUCCESS           Draw keyboard was done.
  @retval EFI_UNSUPPORTED       Did not get key mapping table.

**/
EFI_STATUS
DrawKeyboardLayout (
  IN VK_CONTEXT *VkContext
  )
{
  UINTN                                TopAndBottomSideFramLine;
  UINTN                                KeyButtonHigh;
  UINT32                               KeyButtonWidth;
  UINTN                                OffsetRowAddr;
  UINTN                                OffsetColumnAddr;
  UINTN                                PtrCharIndex;
  EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE    *GraphicsMode;
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
  VKSTRU                               *XmanPtr;
  UINT32                               *FontPtr;
  EFI_STATUS                           Status;
  VIRTUAL_KEYBOARD_PROTOCOL            *VirtualKeyboardLayoutProtocol;
  VK_TABLE_STRU                        *mVkTable;

  GraphicsMode = VkContext->GraphicsOutput->Mode;
  Info = GraphicsMode->Info;

  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) MaxMode: 0x%08x\n", GraphicsMode->MaxMode));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) Mode: 0x%08x\n", GraphicsMode->Mode));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) FrameBufferSize: 0x%08x\n", GraphicsMode->FrameBufferSize));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) Info->HorizontalResolution: 0x%08x\n", Info->HorizontalResolution));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) Info->VerticalResolution: 0x%08x\n", Info->VerticalResolution));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(DrawKeyboardLayout) AbsolutePointer->Mode->AbsoluteMaxY: 0x%08x\n",VkContext->AbsolutePointer->Mode->AbsoluteMaxY));

  Status = gBS->LocateProtocol (&gVirtualKeyboardLayoutProtocolGuid, NULL, (VOID **) &VirtualKeyboardLayoutProtocol);
  if (EFI_ERROR (Status)) {
    mVkTable = VkTable;
  } else {
    mVkTable = (VK_TABLE_STRU *)VirtualKeyboardLayoutProtocol->VirtualKeyboardLayout;
  }

  for (PtrCharIndex = 0; PtrCharIndex < VirtualKeyboardLayoutProtocol->VirtualKeyboardCount; PtrCharIndex++) {
    if ((mVkTable[PtrCharIndex].xResolution == Info->HorizontalResolution) ||\
         mVkTable[PtrCharIndex].yResolution == Info->VerticalResolution) {
        VkContext->XmanPtr = mVkTable[PtrCharIndex].KeyArryPtr;
        XmanPtr = mVkTable[PtrCharIndex].KeyArryPtr;
        VkContext->NumOfKeysInfo = mVkTable[PtrCharIndex].NumOfData;
    }
  }

  if (VkContext->XmanPtr == NULL) {
    //
    // did error handle, the resolution dismatch
    //
    return EFI_UNSUPPORTED;
  }


  //
  // Draw keys layout
  //

  //
  //  ==================== --> TopAndBottomSideFramLine
  //   Key1 , Key2,  Key3
  //                      }-->
  //   Key4 , Key5,  Key6
  //                      }
  //   Key7 , Key8,  Key9
  //                      }
  //   Key10, Key11, Key12
  //                      }
  //   Key13, Key14, Key15
  //                      }
  //   Key16, Key17, Key18
  //                      }
  //   Key19, Key20, Key21
  //  ==================== --> TopAndBottomSideFramLine
  //^
  //+-----Keep width Value "LEFT_AND_RIGHT_SIDE_LINE"

  TopAndBottomSideFramLine = (Info->VerticalResolution % ROW_KEYS_M) / 2;
  KeyButtonWidth = 0;
  KeyButtonHigh = 0;

  OffsetRowAddr = TopAndBottomSideFramLine;
  OffsetColumnAddr = LEFT_AND_RIGHT_SIDE_LINE;

  XmanPtr = VkContext->XmanPtr;

  if (VkContext->ShowTheKeyboard == FALSE) {
    DrawRectangle (
      VkContext->GraphicsOutput,
      XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_StartX + KEY_BOTTOM_WIDTH,
      XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_StartY + KEY_BOTTOM_WIDTH,
      XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_EndX - KEY_BOTTOM_WIDTH + KeyButtonWidth,
      XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_EndY - KEY_BOTTOM_WIDTH + KeyButtonWidth,
      COLOR_LIGHT_GRAY
      );
    GetMappingFont (VkContext, &XmanPtr[VkContext->NumOfKeysInfo - 1], &FontPtr);

    if (FontPtr != NULL) {
      DrawCharacter (
        VkContext->GraphicsOutput,
        XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_StartX + KEY_BOTTOM_WIDTH,
        XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_StartY + KEY_BOTTOM_WIDTH,
        XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_EndX - KEY_BOTTOM_WIDTH + KeyButtonWidth,
        XmanPtr[VkContext->NumOfKeysInfo - 1].Dis_EndY - KEY_BOTTOM_WIDTH + KeyButtonWidth,
        FontPtr,
        0,
        0x01
        );
    }

  } else {
    for (PtrCharIndex = 0; PtrCharIndex < VkContext->NumOfKeysInfo; PtrCharIndex++) {

      //
      //     (X,Y)
      //->>> (OffsetColumnAddr + KEY_BOTTOM_WIDTH, OffsetRowAddr + KEY_BOTTOM_WIDTH)
      //| ............
      //-[.----------.
      //  .|        |.
      //  .|        |.
      //  .|        |.
      //  .|        |.
      //  .|        |.
      //  .----------.
      //  ............]--->(OffsetColumnAddr - KEY_BOTTOM_WIDTH, OffsetRowAddr - KEY_BOTTOM_WIDTH)
      //
      //
      //
      DrawRectangle (
        VkContext->GraphicsOutput,
        XmanPtr[PtrCharIndex].Dis_StartX + KEY_BOTTOM_WIDTH,
        XmanPtr[PtrCharIndex].Dis_StartY + KEY_BOTTOM_WIDTH,
        XmanPtr[PtrCharIndex].Dis_EndX - KEY_BOTTOM_WIDTH + KeyButtonWidth,
        XmanPtr[PtrCharIndex].Dis_EndY - KEY_BOTTOM_WIDTH + KeyButtonWidth,
        COLOR_LIGHT_GRAY
        );

      GetMappingFont (VkContext, &XmanPtr[PtrCharIndex], &FontPtr);
      if (FontPtr != NULL) {
        DrawCharacter (
          VkContext->GraphicsOutput,
          XmanPtr[PtrCharIndex].Dis_StartX + KEY_BOTTOM_WIDTH,
          XmanPtr[PtrCharIndex].Dis_StartY + KEY_BOTTOM_WIDTH,
          XmanPtr[PtrCharIndex].Dis_EndX - KEY_BOTTOM_WIDTH + KeyButtonWidth,
          XmanPtr[PtrCharIndex].Dis_EndY - KEY_BOTTOM_WIDTH + KeyButtonWidth,
          FontPtr,
          0,
          0x01
          );
      }

    } // for (PtrCharIndex = 0; PtrCharIndex < DIM(Xman); PtrCharIndex++) { end this

  } //   if (VkContext->ShowTheKeyboard == FALSE) { end this

  return EFI_SUCCESS;
}

/**
  Start the virtual keyboard driver

  This routine allocates the necessary resources for the driver.

  This routine is called by VirtualKeyboardDriverStart to complete the driver
  initialization.

  @param [in] VkContext       Address of an VK_CONTEXT structure
  @param[in] Controller       Handle to the controller

  @retval EFI_SUCCESS         Driver API properly initialized

**/
EFI_STATUS
VkApiStart (
  IN VK_CONTEXT           *VkContext,
  IN EFI_HANDLE           Controller
  )
{
  EFI_GRAPHICS_OUTPUT_PROTOCOL             *GraphicsOutput;
  EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE        *GraphicsMode;
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION     *Info;
  EFI_ABSOLUTE_POINTER_MODE                *PointerMode;
  EFI_STATUS                               Status;
  EFI_STATUS                               StatusEx;
  UINT32                                   ConOutRow;
  UINT32                                   SetupConOutRow;
  UINT32                                   VirtualKeyboardHeight;

  //
  // Display entry
  //
  DEBUG (( DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart entered\n" ));

  //
  // Create the wait event
  //
  Status = gBS->CreateEvent (
                  EVT_NOTIFY_WAIT,
                  TPL_NOTIFY,
                  TouchVkWaitForKey,
                  VkContext,
                  &VkContext->SimpleTextIn.WaitForKey
                  );

  StatusEx = gBS->CreateEvent (
                    EVT_NOTIFY_WAIT,
                    TPL_NOTIFY,
                    TouchVkWaitForKey,
                    VkContext,
                    &(VkContext->SimpleInputEx.WaitForKeyEx)
                    );

  Status = Status | StatusEx;
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ERROR - Failed to create the input event, Status: %r\n", Status));
    goto ErrorExit;
  }

  VkContext->ShowTheKeyboard = FALSE;
  VkContext->PageNumber = 0;

  //
  // Update text mode PCD.
  //
  ConOutRow           = PcdGet32 (PcdConOutRow);
  SetupConOutRow      = PcdGet32 (PcdSetupConOutRow);
  VirtualKeyboardHeight  = 10;
  if (ConOutRow != SetupConOutRow) {
    //
    // In case SetMode fail.
    //
    ConOutRow = SetupConOutRow;
  }
  PcdSet32S (PcdConOutRow, ConOutRow - VirtualKeyboardHeight);
  PcdSet32S (PcdSetupConOutRow, SetupConOutRow - VirtualKeyboardHeight);

  //
  // Draw Virtual keyboard
  //
  DrawKeyboardLayout (VkContext);

  //
  //  Create the wait event
  //
  Status = gBS->CreateEvent (
                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
                  TPL_VK_SYNC,
                  &VkTimer,
                  (VOID *)VkContext,
                  &VkContext->TimerEvent
                  );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ERROR - Failed to create the timer event, Status: %r\n", Status));
    goto ErrorExit;
  }

  //
  //  Display the graphics data
  //
  GraphicsOutput = VkContext->GraphicsOutput;
  GraphicsMode = GraphicsOutput->Mode;
  Info = GraphicsMode->Info;
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(VkApiStart) MaxMode: 0x%08x\n",                    GraphicsMode->MaxMode));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(VkApiStart) Mode: 0x%08x\n",                       GraphicsMode->Mode));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(VkApiStart) Info->HorizontalResolution: 0x%08x\n", Info->HorizontalResolution));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "(VkApiStart) Info->VerticalResolution: 0x%08x\n",   Info->VerticalResolution));

  //
  // Get the frame buffer
  //
  VkContext->FrameBuffer = (UINT32 *)(UINTN)GraphicsMode->FrameBufferBase;

  //
  // Determine the four corners of the display
  //
  VkContext->DisplayTop = 0;
  VkContext->DisplayBottom = Info->VerticalResolution - 1;
  VkContext->YSign = ( VkContext->DisplayTop > VkContext->DisplayBottom ) ? 1 : -1;
  VkContext->YIncrement = -(INT32)Info->PixelsPerScanLine;
  VkContext->YExtra = - (INT32)( Info->PixelsPerScanLine - Info->VerticalResolution );
  VkContext->DisplayLeft = 0;
  VkContext->DisplayRight = Info->HorizontalResolution - 1;
  VkContext->XSign = ( VkContext->DisplayRight > VkContext->DisplayLeft ) ? 1 : -1;
  VkContext->XIncrement = 1;
  VkContext->XExtra = 0;

  //
  // Display the soft keyboard
  //
  VkContext->DisplayKeyboard = TRUE;

  //
  // Display the pointer data
  //
  PointerMode = VkContext->AbsolutePointer->Mode;
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "X: 0x%016Lx - 0x%016Lx\n", PointerMode->AbsoluteMinX, PointerMode->AbsoluteMaxX));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "Y: 0x%016Lx - 0x%016Lx\n", PointerMode->AbsoluteMinY, PointerMode->AbsoluteMaxY));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "Z: 0x%016Lx - 0x%016Lx\n", PointerMode->AbsoluteMinZ, PointerMode->AbsoluteMaxZ));
  DEBUG ((DEBUG_VK_GRAPHICS_INFO, "Attributes: 0x%08x\n",     PointerMode->Attributes));

  //
  // Determine the touch coordinates
  //
  VkContext->TouchLeft = PointerMode->AbsoluteMinX;
  VkContext->TouchRight = PointerMode->AbsoluteMaxX;
  VkContext->TouchTop = PointerMode->AbsoluteMinY;
  VkContext->TouchBottom = PointerMode->AbsoluteMaxY;

  //
  // Set key buffer
  //
  VkContext->KeyStartIndex = 0;
  VkContext->KeyEndIndex = 0;

  //
  // Start the timer
  //
  Status = gBS->SetTimer (
                  VkContext->TimerEvent,
                  TimerPeriodic,
                  (UINT64)VK_POLL_INTERVAL
                  );
  if (EFI_ERROR (Status)) {
    goto ErrorExit;
  }

  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Success, Status: %r\n", Status));
  return Status;

ErrorExit:

  if ((VkContext != NULL) && (VkContext->AbsolutePointer->WaitForInput != NULL)) {
    gBS->CloseEvent (VkContext->AbsolutePointer->WaitForInput);
  }

  if ((VkContext != NULL) && (VkContext->SimpleTextIn.WaitForKey != NULL)) {
    gBS->CloseEvent (VkContext->SimpleTextIn.WaitForKey);
  }

  if ((VkContext != NULL) && (VkContext->SimpleInputEx.WaitForKeyEx != NULL)) {
    gBS->CloseEvent (VkContext->SimpleInputEx.WaitForKeyEx);
  }

  if ((VkContext != NULL) && (VkContext->TimerEvent != NULL)) {
    gBS->CloseEvent (VkContext->TimerEvent);
  }

  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart fail, Status: %r\n", Status));
  return Status;
}


/**
  Stop the virtual keyboard driver

  This routine releases the resources allocated by VKApiStart.

  This routine is called by VirtualKeyboardDriverStop to initiate the driver
  shutdown.

  @param [in] VkContext       Address of an VK_CONTEXT structure

**/
VOID
VkApiStop (
  IN VK_CONTEXT *VkContext
  )
{
  EFI_STATUS Status;

  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop entered\n"));

  //
  // Stop the timer
  //
  Status = gBS->SetTimer (VkContext->TimerEvent, TimerCancel, 0);
  ASSERT (Status == EFI_SUCCESS);
  Status = gBS->CloseEvent (VkContext->TimerEvent);
  ASSERT (Status == EFI_SUCCESS);

  //
  // Done with the events
  //
  Status = gBS->CloseEvent (VkContext->SimpleTextIn.WaitForKey);
  VkContext->SimpleTextIn.WaitForKey = NULL;
  ASSERT (Status == EFI_SUCCESS);
  Status = gBS->CloseEvent (VkContext->SimpleInputEx.WaitForKeyEx);
  VkContext->SimpleInputEx.WaitForKeyEx = NULL;
  ASSERT (Status == EFI_SUCCESS);

  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop exiting\n"));
}


//
// Simple Text Input Ex protocol functions
//
/**
  Resets the input device hardware.

  The Reset() function resets the input device hardware. As part
  of initialization process, the firmware/device will make a quick
  but reasonable attempt to verify that the device is functioning.
  If the ExtendedVerification flag is TRUE the firmware may take
  an extended amount of time to verify the device is operating on
  reset. Otherwise the reset operation is to occur as quickly as
  possible. The hardware verification process is not defined by
  this specification and is left up to the platform firmware or
  driver to implement.

  @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.

  @param ExtendedVerification Indicates that the driver may perform a more exhaustive
                              verification operation of the device during reset.

  @retval EFI_SUCCESS         The device was reset.
  @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.

**/
EFI_STATUS
EFIAPI
VkKeyboardResetEx (
  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
  IN BOOLEAN                            ExtendedVerification
  )
{
  EFI_STATUS                Status;
  VK_CONTEXT                *VkContext;


  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(This);


  Status = VkContext->SimpleTextIn.Reset (&VkContext->SimpleTextIn, ExtendedVerification);
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;

}

/**
  Reads the next keystroke from the input device.

  @param  This                   Protocol instance pointer.
  @param  KeyData                A pointer to a buffer that is filled in with the keystroke
                                 state data for the key that was pressed.

  @retval EFI_SUCCESS            The keystroke information was returned.
  @retval EFI_NOT_READY          There was no keystroke data available.
  @retval EFI_DEVICE_ERROR       The keystroke information was not returned due to
                                 hardware errors.
  @retval EFI_INVALID_PARAMETER  KeyData is NULL.

**/
EFI_STATUS
EFIAPI
VkKeyboardReadKeyStrokeEx (
  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
  OUT EFI_KEY_DATA                      *KeyData
  )
{
  VK_CONTEXT        *VkContext;
  EFI_STATUS        Status;

  if (KeyData == NULL) {
    return EFI_INVALID_PARAMETER;
  }


  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(This);

  DEBUG (( DEBUG_VK_POINTS, "@[%x]<%x>", VkContext->KeyStartIndex, VkContext->KeyEndIndex ));

  if (VkContext->KeyStartIndex == VkContext->KeyEndIndex) {

    return EFI_NOT_READY;
  }

  Status = VkReadKeyBuf(VkContext->Keybuffer,
                        VkContext->AltKeyBuf,
                        &VkContext->KeyStartIndex,
                        &VkContext->KeyEndIndex,
                        KeyData
                       );

  if (EFI_ERROR(Status)) {
    Status = EFI_NOT_READY;
  }

  DEBUG (( DEBUG_VK_POINTS, "{%x}", KeyData->Key.ScanCode ));

  return EFI_SUCCESS;

}

/**
  Set certain state for the input device.

  @param  This                    Protocol instance pointer.
  @param  KeyToggleState          A pointer to the EFI_KEY_TOGGLE_STATE to set the
                                  state for the input device.

  @retval EFI_SUCCESS             The device state was set appropriately.
  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could
                                  not have the setting adjusted.
  @retval EFI_UNSUPPORTED         The device does not support the ability to have its state set.
  @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.

**/
EFI_STATUS
EFIAPI
VkKeyboardSetState (
  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
  )
{
  VK_CONTEXT                *VkContext;

  if (KeyToggleState == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(This);

  DEBUG (( DEBUG_VK_POINTS, "\n SetState--> KeyToggleState=%x", *KeyToggleState ));

  return EFI_SUCCESS;

}

/**
  Register a notification function for a particular keystroke for the input device.

  @param  This                        Protocol instance pointer.
  @param  KeyData                     A pointer to a buffer that is filled in with the keystroke
                                      information data for the key that was pressed.
  @param  KeyNotificationFunction     Points to the function to be called when the key
                                      sequence is typed specified by KeyData.
  @param  NotifyHandle                Points to the unique handle assigned to the registered notification.

  @retval EFI_SUCCESS                 The notification function was registered successfully.
  @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.
  @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.

**/
EFI_STATUS
EFIAPI
VkKeyboardRegisterKeyNotify (
  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
  IN  EFI_KEY_DATA                       *KeyData,
  IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
  OUT EFI_HANDLE                         *NotifyHandle
  )
{
  VK_CONTEXT                *VkContext;

  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(This);

  DEBUG (( DEBUG_VK_POINTS, "\n RegisterKeyNotify\n"));

  return EFI_SUCCESS;

}

/**
  Remove a registered notification function from a particular keystroke.

  @param  This                      Protocol instance pointer.
  @param  NotificationHandle        The handle of the notification function being unregistered.

  @retval EFI_SUCCESS              The notification function was unregistered successfully.
  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid

**/
EFI_STATUS
EFIAPI
VkKeyboardUnregisterKeyNotify (
  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
  IN EFI_HANDLE                         NotificationHandle
  )
{
  VK_CONTEXT                *VkContext;

  if (NotificationHandle == NULL) {
    return EFI_INVALID_PARAMETER;
  }


  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(This);
  DEBUG (( DEBUG_VK_POINTS, "\n UnregisterKeyNotify\n"));

  return EFI_SUCCESS;
}
